using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

class SDFRenderPass : ScriptableRenderPass
{
    public RenderTextureDescriptor   m_DestTexture;
    public RenderTextureDescriptor   m_DestSourceTexture2;
    public RenderTargetIdentifier   m_Source;
    private RTHandle tempTextureHandle;
    private RTHandle sourceTextureHandle2;
    private Material m_Material;
    private ComputeBuffer m_ComputeBuffer;
    private SDFRenderFeature.SDFShapeSetting m_Setting;
    private ShapeDataProvider m_DataProvider = new ShapeDataProvider();
    public SDFRenderPass(Material material, SDFRenderFeature.SDFShapeSetting setting)
    {
        m_Setting = setting;
        renderPassEvent = setting.passEvent;
        m_Material = material;
        m_DestTexture = new RenderTextureDescriptor(Screen.width,
            Screen.height, RenderTextureFormat.Default, 0);
        m_DestSourceTexture2 = new RenderTextureDescriptor(Screen.width,
            Screen.height, RenderTextureFormat.Default, 0);

        ShapeSDFManager.Instance.SetDataProvider(m_DataProvider);
    }
    // GPU缓冲区
    // This method is called before executing the render pass.
    // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
    // When empty this render pass will render to the active camera render target.
    // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
    // The render pipeline will ensure target setup and clearing happens in a performant manner.
    public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
    {
    }
    public override void Configure(CommandBuffer cmd,
        RenderTextureDescriptor cameraTextureDescriptor)
    {
        // 中间纹理的配置，这里分辨率做动态缩放（性能优化）
        m_DestTexture.width = (int)(cameraTextureDescriptor.width / m_Setting.resolutionDivisor);
        m_DestTexture.height = (int)(cameraTextureDescriptor.height / m_Setting.resolutionDivisor);
        m_DestTexture.colorFormat = RenderTextureFormat.DefaultHDR;// 为了Bloom的光效，开启HDR
        m_DestSourceTexture2.width = cameraTextureDescriptor.width ;
        m_DestSourceTexture2.height = cameraTextureDescriptor.height;

        // 创建中间纹理
        RenderingUtils.ReAllocateIfNeeded(ref tempTextureHandle, m_DestTexture);
        RenderingUtils.ReAllocateIfNeeded(ref sourceTextureHandle2, m_DestSourceTexture2);
        ConfigureTarget(tempTextureHandle);
        ConfigureClear(ClearFlag.Color, Color.clear);
    }

    private int m_PreviousShapeDataCount = 0;
    // Here you can implement the rendering logic.
    // Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
    // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
    // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {

        // SDFRenderFeature.ShapeData[] shapesData = m_DataProvider.GetShapeDataForRender();
        SDFRenderFeature.ShapeData[] shapesData = ShapeSDFManager.Instance.GetShapesData();
        if (shapesData == null || shapesData.Length == 0)
        {
            return;
        }
        
        var camera = renderingData.cameraData.camera;
        m_Material.SetFloat("_DegreeOfFuse", m_Setting.degreeOfFusion);
        m_Material.SetFloat("_DistabilizationAmplitude", m_Setting.distabilizationAmplitude);
        m_Material.SetFloat("_DistabilizationFraquence", m_Setting.distabilizationFraquence);
        m_Material.SetFloat("_DistabilizationSpeed", m_Setting.distabilizationSpeed);
        
        // 从池中获取 CommandBuffer
        RTHandle cameraTargetHandle = renderingData.cameraData.renderer.cameraColorTargetHandle;
        CommandBuffer cmd = CommandBufferPool.Get("SDFRenderPass");
        cmd.Clear();
        if (shapesData.Length != m_PreviousShapeDataCount || m_ComputeBuffer == null)
        {// 避免每次都重新创建缓冲区
            m_PreviousShapeDataCount = shapesData.Length;
            if(m_ComputeBuffer != null)
                m_ComputeBuffer.Dispose();
            m_ComputeBuffer = new ComputeBuffer(shapesData.Length, SDFRenderFeature.ShapeData.GetSize() );
        }
        
        m_ComputeBuffer.SetData(shapesData); 
        
        Blitter.BlitCameraTexture(cmd, cameraTargetHandle, sourceTextureHandle2);
        cmd.SetGlobalTexture("_SourceTexture",  sourceTextureHandle2);// 渲染SDF之前的画面，用于第二个pass和SDF渲染的画面做融合
        cmd.SetGlobalBuffer("_ShapeDataBuffer", m_ComputeBuffer);
        
        Blitter.BlitCameraTexture(cmd, cameraTargetHandle, tempTextureHandle, m_Material, 0);
        cmd.SetGlobalTexture("_MainTex", tempTextureHandle);// 不知道为啥不会将图像自动传进去，这里手动传一下
        Blitter.BlitCameraTexture(cmd, tempTextureHandle, cameraTargetHandle, m_Material, 1);
        
        cmd.SetGlobalInt("_ShapeDataCount", shapesData.Length);
        // 执行命令缓冲区并释放回池
        context.ExecuteCommandBuffer(cmd);
        cmd.Clear();
        CommandBufferPool.Release(cmd);
    }

    // Cleanup any allocated resources that were created during the execution of this render pass.
    public override void OnCameraCleanup(CommandBuffer cmd)
    {
        // tempTextureHandle.Release();
    }
    public void Dispose()
    {
#if UNITY_EDITOR
        if (EditorApplication.isPlaying)
        {
            Object.Destroy(m_Material);
        }
        else
        {
            Object.DestroyImmediate(m_Material);
        }
#else
            Object.Destroy(m_Material);
#endif

        if (tempTextureHandle != null) tempTextureHandle.Release();
    }
}